extern "C" {
    pub fn printstr(p : *const u8, l : u32);
    fn print_str_endwith_enter(p : *const u8, l : u32);
}

// 定义栈寄存器的结构体
#[repr(C)]
pub struct StackFrame {
    pub gs : u32,
    pub fs : u32,
    pub es : u32,
    pub ds : u32,
    pub edi : u32,
    pub esi : u32,
    pub ebp : u32,
    pub kernel_esp : u32,
    pub ebx : u32,
    pub edx : u32,
    pub ecx : u32,
    pub eax : u32,
    pub retaddr : u32,
    pub eip : u32,
    pub cs : u32,
    pub eflags : u32,
    pub esp : u32,
    pub ss : u32,
}
impl StackFrame {
    pub fn new() ->  StackFrame{
        StackFrame {
            gs:0, fs:0, es:0, ds:0, edi:0, esi:0, ebp:0, kernel_esp:0, ebx:0,
            edx:0, ecx:0, eax:0, retaddr:0, eip:0, cs:0, eflags:0, esp:0, ss:0,
        }
    }
}

const LDT_DESC_NUM : usize = 4;
const LDT_SIZE : usize = LDT_DESC_NUM << 1;
#[repr(C)]
pub struct Process<'a> {
    pub regs : StackFrame,
    pub reserve : u16,
    pub ldt_sel : u16,                                      // LDT 段选择符
    pub ldts : [u32; LDT_SIZE],                             // 段描述符
    pub pid : u32,                                          // 进程ID
    pub name : &'a str,                                     // 进程名称
    pub priority: u32,                                      // 进程优先级
    pub ticks: u32,                                         // 进程剩余ticks
}


impl Process<'_> {
    pub fn new(regs:StackFrame, ldt_sel:u16, ldts:[u32; LDT_SIZE], pid:u32, name:&str, priority: u32) -> Process {
        let mut p = Process { regs:regs, reserve: 0, ldt_sel:ldt_sel, ldts:ldts, pid:pid, name:name, priority:priority, ticks: priority };
        p.regs.gs = (USER_DS << 3 )+ 0x7;
        p.regs.fs = (USER_DS << 3 ) + 0x7;
        p.regs.es = (USER_DS << 3 ) + 0x7;
        p.regs.ds = (USER_DS << 3 ) + 0x7;
        p
    }
}

pub fn task_init() {
    // 创建新的任务
    create_task();

    unsafe {
        let _dispstr = "Task init ok.";
        print_str_endwith_enter(_dispstr.as_ptr(), _dispstr.len().try_into().unwrap());
    }
}

#[no_mangle]
pub extern "C" fn delay() {
    for _x in 0..100 {
        for _y in 0..200 {
            for _z in 0..200 {
            }
        }
    } 
}

pub fn delay_ms(ms: u32) {
    // 时钟中断10ms每次
    let start = crate::system::idt::get_ticks();
    loop {
        if ((crate::system::idt::get_ticks() - start) * 10) >= ms {
            break;
        }
    }
}

#[no_mangle]
pub extern "C" fn task0_run() {
    loop {
        unsafe {
            let _dispstr = ".T0.";
            //printstr(_dispstr.as_ptr(), _dispstr.len().try_into().unwrap());
        }
        delay_ms(1000);
    }
}

#[no_mangle]
pub extern "C" fn task1_run() {
    loop {
        unsafe {
            let _dispstr = ".T1.";
            //printstr(_dispstr.as_ptr(), _dispstr.len().try_into().unwrap());
        }
        delay_ms(1000);
    }
}

#[no_mangle]
pub extern "C" fn task2_run() {
    loop {
        unsafe {
            let _dispstr = ".T2.";
            //printstr(_dispstr.as_ptr(), _dispstr.len().try_into().unwrap());
        }
        delay_ms(1000);
    }
}


use crate::system::gdt::{gdt_desc_entry_init, ldt_desc_entry_init};
pub const PROCESS_NUMBER : usize = 3;
pub static mut PROCESS: [Option<Process>; PROCESS_NUMBER] = [None, None, None];
const ENTRY_POINT: [extern "C" fn(); PROCESS_NUMBER] = [task0_run, task1_run, task2_run];
const USER_STACK_TOP_BASE: u32 = 0xF00000;
const USER_STACK_SIZE: u32 = 0x1000;
fn create_task() {
    for i in 0..PROCESS_NUMBER {
        let task = Process::new(StackFrame::new(),
                                    get_offset_of_ldt(i),
                                    [0; LDT_SIZE],
                                    i as u32, "task",
                                (i as u32 + 1) * 150);
        unsafe {
            PROCESS[i] = Some(task);
        }

        create_default_task_detail(i);
    }
}


fn get_offset_of_ldt(nr: usize) -> u16 {
    ((nr + TASK_OFFSET_IN_GDT_ENTRY) << 3) as u16
}

const USER_CS: u32 = 0x1;         // 用户代码段选择符
const USER_DS: u32 = 0x2;         // 用户数据段选择符
const USER_STACK: u32 = 0x3;      // 用户堆栈段选择符
const TASK_OFFSET_IN_GDT_ENTRY:usize = 9;
fn create_default_task_detail(nr: usize) {
    let idx: usize = nr + TASK_OFFSET_IN_GDT_ENTRY;

    unsafe {    // 特殊处理
        match PROCESS[nr].as_mut() {
            Some(p) => {
                p.regs.cs = ((USER_CS << 3) + 0x7) as u32;
                p.regs.eflags = 0x1202;
                p.regs.esp = (USER_STACK_TOP_BASE + USER_STACK_SIZE * (nr as u32)) as u32;
                p.regs.ss = ((USER_STACK << 3) + 0x7) as u32;
                p.regs.eip = ENTRY_POINT[nr] as *const fn() as u32;
                
                // 在GDT中初始化LDT
                gdt_desc_entry_init(idx as u32 , 
                                p.ldts.as_ptr() as u32, 
                                (LDT_SIZE * 4 - 1) as u32, 
                                0x0082); // LDT描述符
            },
            _ => {},
        };
    }

    // 初始化任务nr的LDT
    ldt_desc_entry_init(nr, 0, 0, 0, 0);                              // LDT表第0项全部为0，保留
    ldt_desc_entry_init(nr, USER_CS, 0, 0x000FFFFF, 0xC0FA);          // LDT表第1项:代码段 00CF FA00 0000 FFFF
    ldt_desc_entry_init(nr, USER_DS, 0, 0x000FFFFF, 0xC0F3);          // LDT表第2项:数据段 00CF F300 0000 FFFF
    ldt_desc_entry_init(nr, USER_STACK, 0, 0x000FFFF, 0xC0F3);        // LDT表第3项:堆栈段 00C0 F300 0000 FFFF
}